/*
 * ControladorR14Consumidor.h
 *
 *  Created on: Nov 19, 2013
 *      Author: m
 */

#ifndef CONTROLADORR14CONSUMIDOR_H_
#define CONTROLADORR14CONSUMIDOR_H_

#include "ICinta13A.h"
#include "ICinta13B.h"
#include "IRobot11A.h"
#include "IRobot11B.h"
#include "IRobot14.h"

#include "Cinta13A.h"
#include "Cinta13B.h"
#include "Robot11AProductor.h"
#include "Robot11BProductor.h"
#include "Robot14Consumidor.h"
#include "DSMManager.h"

class ControladorR14Consumidor :
        public ICinta13A, public ICinta13B, public IRobot11A,
        public IRobot11B, public IRobot14
{
protected:
    Cinta13A m_cinta13A;
    Cinta13B m_cinta13B;
    Robot11AProductor m_robot11A;
    Robot11BProductor m_robot11B;
    Robot14Consumidor m_robot14;

    bool m_primerAvanceCinta13A;
    bool m_primerAvanceCinta13B;

    void tomarCinta13A()
    {
        // Si el productor esta usando la cinta espero a que termine
        if ( m_cinta13A.getCinta()->productorUsando() )
        {
            m_cinta13A.getCinta()->setConsumidorEsperando( true );

            m_cinta13A.terminarExclusionMutua();

            m_cinta13A.dormirConsumidor();

            m_cinta13A.iniciarExclusionMutua();
        }
        else
        {
            m_cinta13A.getCinta()->setConsumidorUsando( true );
        }
    }

    void tomarCinta13B()
    {
        // Si el productor esta usando la cinta espero a que termine
        if ( m_cinta13B.getCinta()->productorUsando() )
        {
            m_cinta13B.getCinta()->setConsumidorEsperando( true );

            m_cinta13B.terminarExclusionMutua();

            m_cinta13B.dormirConsumidor();

            m_cinta13B.iniciarExclusionMutua();
        }
        else
        {
            m_cinta13B.getCinta()->setConsumidorUsando( true );
        }
    }

    void liberarCinta13A()
    {
        m_cinta13A.getCinta()->setConsumidorUsando( false );

        if ( m_cinta13A.getCinta()->productorEsperando() )
        {
            m_cinta13A.getCinta()->setProductorEsperando( false );

            m_cinta13A.getCinta()->setProductorUsando( true );

            m_cinta13A.despertarProductor();
        }
    }

    void liberarCinta13B()
    {
        m_cinta13B.getCinta()->setConsumidorUsando( false );

        if ( m_cinta13B.getCinta()->productorEsperando() )
        {
            m_cinta13B.getCinta()->setProductorEsperando( false );

            m_cinta13B.getCinta()->setProductorUsando( true );

            m_cinta13B.despertarProductor();
        }
    }

public:
    ControladorR14Consumidor() :
        m_primerAvanceCinta13A( true ),
        m_primerAvanceCinta13B( true )
    {
        DSMManager::inicializar("robot14con");
    }

    virtual ~ControladorR14Consumidor()
    {
    }

    bool c13a_tieneElementos()
    {
        bool tieneElementos;

        m_primerAvanceCinta13A = true;

        m_cinta13A.iniciarExclusionMutua();

        this->tomarCinta13A();

        tieneElementos = m_cinta13A.getCinta()->tieneElementos();

        m_cinta13A.terminarExclusionMutua();

        return tieneElementos;
    }

    int c13a_contarElementos()
    {
        int nElementos;

        m_cinta13A.iniciarExclusionMutua();

        nElementos = m_cinta13A.getCinta()->contarElementos();

        // libera la cinta
        this->liberarCinta13A();

        m_cinta13A.terminarExclusionMutua();

        return nElementos;
    }

    bool c13a_avanzar()
    {
        bool avanzoOk;

        m_cinta13A.iniciarExclusionMutua();

        // Si es la primera vez que avanza, toma la cinta
        if ( m_primerAvanceCinta13A )
        {
            m_primerAvanceCinta13A = false;

            this->tomarCinta13A();
        }

        avanzoOk = m_cinta13A.getCinta()->avanzar();

        m_cinta13A.terminarExclusionMutua();

        return avanzoOk;
    }

    ElementoProduccion c13a_quitar()
    {
        ElementoProduccion elem;

        m_cinta13A.iniciarExclusionMutua();

        elem = m_cinta13A.getCinta()->quitar();

        m_cinta13A.terminarExclusionMutua();

        return elem;
    }

    bool c13b_tieneElementos()
    {
        bool tieneElementos;

        m_primerAvanceCinta13B = true;

        m_cinta13B.iniciarExclusionMutua();

        this->tomarCinta13B();

        tieneElementos = m_cinta13B.getCinta()->tieneElementos();

        m_cinta13B.terminarExclusionMutua();

        return tieneElementos;
    }

    int c13b_contarElementos()
    {
        int nElementos;

        m_cinta13B.iniciarExclusionMutua();

        nElementos = m_cinta13B.getCinta()->contarElementos();

        // libera la cinta
        this->liberarCinta13B();

        m_cinta13B.terminarExclusionMutua();

        return nElementos;
    }

    bool c13b_avanzar()
    {
        bool avanzoOk;

        m_cinta13B.iniciarExclusionMutua();

        // Si es la primera vez que avanza, toma la cinta
        if ( m_primerAvanceCinta13B )
        {
            m_primerAvanceCinta13B = false;

            this->tomarCinta13B();
        }

        avanzoOk = m_cinta13B.getCinta()->avanzar();

        m_cinta13B.terminarExclusionMutua();

        return avanzoOk;
    }

    ElementoProduccion c13b_quitar()
    {
        ElementoProduccion elem;

        m_cinta13B.iniciarExclusionMutua();

        elem = m_cinta13B.getCinta()->quitar();

        m_cinta13B.terminarExclusionMutua();

        return elem;
    }

    bool r11a_esperaEspacioVacio()
    {
        bool esperaEspacioVacio;

        m_robot11A.iniciarExclusionMutua();
        esperaEspacioVacio = m_robot11A.esperaEspacio();
        m_robot11A.terminarExclusionMutua();

        return esperaEspacioVacio;
    }

    void r11a_notificarEspacioVacio()
    {
        m_cinta13A.iniciarExclusionMutua();

        m_robot11A.iniciarExclusionMutua();
        m_robot11A.setEsperaEspacio( false );
        m_robot11A.despertar();
        m_robot11A.terminarExclusionMutua();

        m_cinta13A.getCinta()->setConsumidorUsando( false );
        m_cinta13A.getCinta()->setConsumidorEsperando( true );

        m_cinta13A.despertarProductor();

        m_cinta13A.terminarExclusionMutua();

        m_cinta13A.dormirConsumidor();
    }

    void r11a_notificarQuiteElemento()
    {
        m_cinta13A.iniciarExclusionMutua();
        m_robot11A.iniciarExclusionMutua();

        if ( m_robot11A.esperaEspacio() )
        {
            m_robot11A.setEsperaEspacio( false );
            m_robot11A.despertar();
            m_cinta13A.getCinta()->setProductorEsperando( true );
        }

        m_robot11A.terminarExclusionMutua();

        // Libera la cinta 13A
        this->liberarCinta13A();
        m_cinta13A.terminarExclusionMutua();
    }

    bool r11b_esperaEspacioVacio()
    {
        bool esperaEspacioVacio;

        m_robot11B.iniciarExclusionMutua();
        esperaEspacioVacio = m_robot11B.esperaEspacio();
        m_robot11B.terminarExclusionMutua();

        return esperaEspacioVacio;
    }

    void r11b_notificarEspacioVacio()
    {
        m_cinta13B.iniciarExclusionMutua();

        m_robot11B.iniciarExclusionMutua();
        m_robot11B.setEsperaEspacio( false );
        m_robot11B.despertar();
        m_robot11B.terminarExclusionMutua();

        m_cinta13B.getCinta()->setConsumidorUsando( false );
        m_cinta13B.getCinta()->setConsumidorEsperando( true );

        m_cinta13B.despertarProductor();

        m_cinta13B.terminarExclusionMutua();

        m_cinta13B.dormirConsumidor();
    }

    void r11b_notificarQuiteElemento()
    {
        m_cinta13B.iniciarExclusionMutua();
        m_robot11B.iniciarExclusionMutua();

        if ( m_robot11B.esperaEspacio() )
        {
            m_robot11B.setEsperaEspacio( false );
            m_robot11B.despertar();
            m_cinta13B.getCinta()->setProductorEsperando( true );
        }

        m_robot11B.terminarExclusionMutua();

        // Libera la cinta 13B
        this->liberarCinta13B();
        m_cinta13B.terminarExclusionMutua();
    }

    void r14_esperarNuevoElemento()
    {
        // Actualiza el estado de R14
        m_robot14.iniciarExclusionMutua();
        m_robot14.setEsperaProducto( true );
        m_robot14.terminarExclusionMutua();

        // Libera las cintas
        m_cinta13A.iniciarExclusionMutua();
        this->liberarCinta13A();
        m_cinta13A.terminarExclusionMutua();

        m_cinta13B.iniciarExclusionMutua();
        this->liberarCinta13B();
        m_cinta13B.terminarExclusionMutua();

        // Espera en el semaforo correspondiente
        m_robot14.dormir();

        // toma nuevamente las cintas
        m_cinta13A.iniciarExclusionMutua();
        this->tomarCinta13A();
        m_cinta13A.terminarExclusionMutua();

        m_cinta13B.iniciarExclusionMutua();
        this->tomarCinta13B();
        m_cinta13B.terminarExclusionMutua();
    }




    bool c13a_depositar( const ElementoProduccion &e )
    {
        throw Exception("Metodo no implementado");
    }

    bool c13b_depositar( const ElementoProduccion &e )
    {
        throw Exception("Metodo no implementado");
    }

    void r11a_esperarEspacioVacio()
    {
        throw Exception("Metodo no implementado");
    }

    void r11b_esperarEspacioVacio()
    {
        throw Exception("Metodo no implementado");
    }

    void r14_notificarNuevoElemento()
    {
        throw Exception("Metodo no implementado");
    }

    bool r14_esperaNuevoElemento()
    {
        throw Exception("Metodo no implementado");
    }

    bool r14_esperaEspacioVacio()
    {
        throw Exception("Metodo no implementado");
    }

    void r14_notificarEspacioVacio()
    {
        throw Exception("Metodo no implementado");
    }

    void r14_notificarQuiteElemento()
    {
        throw Exception("Metodo no implementado");
    }

    void r14_esperarEspacioVacio()
    {
        throw Exception("Metodo no implementado");
    }
};

#endif /* CONTROLADORR14CONSUMIDOR_H_ */
